
--# Test
--# Main
-- Skyrays Lighting
displayMode(OVERLAY)

function setup()
    print("----\nDrag to move the image\nDouble-tap to zoom in/out\nZoom is kinda broken, sorry\n----")
    sidebarTween = tween.delay(1.5, function()
        displayMode(FULLSCREEN)
    end)
    shouldSidebar = 0
    parameter.watch("FPS")
    parameter.number("Samples", 0, 5, 0.5, callback)-- The shader can have the samples set to any amount, but 5 is the most I would recommend. 2 is a good mumber IMO, not too little that it looks really weird, but not too many that it's super laggy
    parameter.boolean("Realistic Curve", true, callback) -- Whether or not the light effect should amplified realistically
    parameter.boolean("Visible Walls", true, callback) -- Whether the walls should be colored or solid black
    parameter.boolean("Overlay", false, callback) -- Sprite the image over where it would be so you can see it in the dark
    mult = 1.0 -- Multiplier for the resolution of the screen (you can crank it up to 2k resolution on retinas, set the mult to 2)
    screen = image(WIDTH * mult, HEIGHT * mult)
    objects = image(WIDTH * mult, HEIGHT * mult)
    m = mesh()
    rIdx = m:addRect(WIDTH / 2 * mult, HEIGHT / 2 * mult, WIDTH * mult, HEIGHT * mult)
    m.texture = screen
    m.shader = shader(Shaders.Skyrays.vS, Shaders.Skyrays.fS)
    m.shader.point = vec2(0.5, 0.5)
    m.shader.godraySamples = 2
    pos = {x = WIDTH / 8, y = HEIGHT / 2, s = 1}
    img = readImage("Small World:Mine Large") -- The image that is put on the screen to block godrays

    bg = image(WIDTH, HEIGHT)
    setContext(bg, false)
    local xSize = WIDTH / 7
    local ySize = WIDTH / 7
    for x = WIDTH / 2 - (xSize + 100), WIDTH / 2 + (xSize + 100), 100 do
        for y = HEIGHT / 2 - (ySize + 100), HEIGHT / 2 + (ySize + 100), 100 do
            sprite("Platformer Art:Block Brick", x, y, 100)
        end
    end
    setContext()
    math.randomseed(0)
    obj = {}
    for i = 1, 25 do
        table.insert(obj, {math.random(0, WIDTH), math.random(0, HEIGHT)})
    end
end

function callback()
    if FPS ~= 0 then
        tween.stop(sidebarTween)
        shouldSidebar = 10
    end
end

function draw()
    --noSmooth()

    local prev = shouldSidebar
    shouldSidebar = math.max(0, shouldSidebar - DeltaTime)
    if prev ~= 0 and shouldSidebar == 0 then
        displayMode(FULLSCREEN)
    end

    m.shader.samples = Samples
    m.shader.realisticCurve = Realistic_Curve
    m.shader.visibleWalls = Visible_Walls
    --m.shader.objects = objects

    background(119, 182, 200, 255)

    strokeWidth(5)

    setContext(screen, false)
    background(0, 0)
    pushMatrix()
    translate(pos.x, pos.y)
    scale(pos.s)
    translate(-(pos.x), -(pos.y))
    sprite(img, pos.x, pos.y, WIDTH, HEIGHT)
    popMatrix()
    setContext()

    translate(WIDTH / 2, HEIGHT / 2)
    scale(pos.s)
    translate(WIDTH / -2, HEIGHT / -2)

    local xOff = (pos.x / 100 - math.floor(pos.x / 100)) * 100
    local yOff = (pos.y / 100 - math.floor(pos.y / 100)) * 100

    sprite(bg, WIDTH / 2 + xOff, HEIGHT / 2 + yOff)

    for k, v in ipairs(obj) do
        sprite("Cargo Bot:Title Large Crate 1", v[1] + pos.x, v[2] + pos.y, 50)
    end

    -- sprite(objects, WIDTH / 2, HEIGHT / 2, WIDTH, HEIGHT)

    -- scale(1 / mult)

    m:draw()

    resetMatrix()

    if Overlay then
        tint(255, 31)
        sprite(img, pos.x, pos.y, WIDTH, HEIGHT)
        noTint()
    end

    resetMatrix()

    fill(255)
    font("HelveticaNeue-UltraLight")
    fontSize(24)
    textMode(CORNER)
    local str = "FPS: " .. FPS
    local w, h = textSize(str)
    text(str, 5, HEIGHT - h - 5)
end

function touched(touch)
    if touch.state ~= ENDED and touch.state ~= CANCELLED then
        pos.x = pos.x + touch.deltaX
        pos.y = pos.y + touch.deltaY
        displayMode(FULLSCREEN)
    elseif touch.tapCount == 2 then
        tween(1, pos, {s = 3 - pos.s}, tween.easing.bounceOut)
        if shouldSidebar > 0 then
            displayMode(OVERLAY)
        end
    else
        if shouldSidebar > 0 then
            displayMode(OVERLAY)
        end
    end
end

-- FPS counter --

FPS = 0
local frames = 0
local time = 0
tween.delay(0, function()
    local d = draw
    draw = function()
        frames = frames + 1
        if math.floor(ElapsedTime) ~= math.floor(time) then
            FPS = frames - 1
            frames = 1
        end
        time = ElapsedTime
        d()
    end
end)
--# Shaders
Shaders = {
Skyrays = {
vS = [[
//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;

//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = color;
    vTexCoord = texCoord;

    //Multiply the vertex position by our combined transform
    gl_Position = modelViewProjection * position;
}

]],
fS = [[
//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//uniform lowp sampler2D objects;

uniform vec2 point;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

uniform bool realisticCurve;

uniform float samples;

uniform bool visibleWalls;

const float distx = 1.0 / 5.0;
const float texMult = 1.0 / distx;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;

    if (col.a <= 0.5) {
        col = vec4(0.0);
    }

    float targetDist = distance(point, vTexCoord);
    lowp vec4 pointSample = texture2D(texture, point);
    bool startVisible = pointSample.a <= 0.5;

    float light = 0.0;

    float add = max(0.0, 1.0 - targetDist * texMult);
    float objLight = add * col.a;

    if (targetDist <= distx) {
        vec2 dir = normalize(point - vTexCoord);
        bool visible = startVisible || col.a <= 0.5;
        float visibleNum = 0.0;
        float mult;
        int c = 0;
        for (float dist = 0.0; dist <= targetDist; dist += targetDist / (samples * 10.0)) {
            lowp vec4 sample = texture2D(texture, vTexCoord + dir * dist);// + texture2D(objects, vTexCoord + dir * dist);
            mult = min(1.0, (1.0 - sample.a) + 0.2);
            float objMult;
            if (visibleWalls) objMult = min(1.0, (1.0 - sample.a) + 0.85);
            if (sample.a != 0.0) {
                if (sample.a <= 0.5) {
                    visibleNum += 1.0;
                    visible = true;
                }
                if ((visible && startVisible) || (!visible) || sample.a > 0.5) {
                    add *= mult;
                    if (visibleWalls) objLight *= objMult;
                    if (col.a > 0.5) {
                        add *= mult;
                        if (visibleWalls) objLight *= objMult;
                        c++;
                    }
                    if (c > 2) break;
                }
            }
        }

        if (visible) {
            if (realisticCurve) add = pow(add * 1.5, 2.0) / 1.5;
            light += add;
        }
    }

    //Set the output color to the texture color
    if (visibleWalls && col.a > 0.5) {
        //light = (light + 0.1) * 2.0 - 0.1;
        gl_FragColor = mix(vec4(vec3(0.0), 1.0), col, max(0.0, min(1.0, objLight)));
    } else {
        gl_FragColor = mix(vec4(vec3(0.0), 1.0), col, max(0.0, min(1.0, light)));
    }
}

]]
}
}
